<!doctype html>
<html class="no-js" lang="en" data-content_root="./">
  <head><meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width,initial-scale=1"/>
    <meta name="color-scheme" content="light dark"><meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Running LIT in a Docker container" href="docker.html" /><link rel="prev" title="LIT Python API" href="api.html" />

    <!-- Generated with Sphinx 7.3.7 and Furo 2024.05.06 -->
        <title>Frontend Developer Guide - 🔥LIT 1.0 documentation</title>
      <link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
    <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=387cc868" />
    <link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?v=36a5483c" />
    <link rel="stylesheet" type="text/css" href="_static/furo_custom.css?v=6173ce67" />
    
    


<style>
  body {
    --color-code-background: #f8f8f8;
  --color-code-foreground: black;
  
  }
  @media not print {
    body[data-theme="dark"] {
      --color-code-background: #202020;
  --color-code-foreground: #d0d0d0;
  
    }
    @media (prefers-color-scheme: dark) {
      body:not([data-theme="light"]) {
        --color-code-background: #202020;
  --color-code-foreground: #d0d0d0;
  
      }
    }
  }
</style></head>
  <body>
    
    <script>
      document.body.dataset.theme = localStorage.getItem("theme") || "auto";
    </script>
    

<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="svg-toc" viewBox="0 0 24 24">
    <title>Contents</title>
    <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024">
      <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM115.4 518.9L271.7 642c5.8 4.6 14.4.5 14.4-6.9V388.9c0-7.4-8.5-11.5-14.4-6.9L115.4 505.1a8.74 8.74 0 0 0 0 13.8z"/>
    </svg>
  </symbol>
  <symbol id="svg-menu" viewBox="0 0 24 24">
    <title>Menu</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-menu">
      <line x1="3" y1="12" x2="21" y2="12"></line>
      <line x1="3" y1="6" x2="21" y2="6"></line>
      <line x1="3" y1="18" x2="21" y2="18"></line>
    </svg>
  </symbol>
  <symbol id="svg-arrow-right" viewBox="0 0 24 24">
    <title>Expand</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-chevron-right">
      <polyline points="9 18 15 12 9 6"></polyline>
    </svg>
  </symbol>
  <symbol id="svg-sun" viewBox="0 0 24 24">
    <title>Light mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="feather-sun">
      <circle cx="12" cy="12" r="5"></circle>
      <line x1="12" y1="1" x2="12" y2="3"></line>
      <line x1="12" y1="21" x2="12" y2="23"></line>
      <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
      <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
      <line x1="1" y1="12" x2="3" y2="12"></line>
      <line x1="21" y1="12" x2="23" y2="12"></line>
      <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
      <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
    </svg>
  </symbol>
  <symbol id="svg-moon" viewBox="0 0 24 24">
    <title>Dark mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-moon">
      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
      <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
    </svg>
  </symbol>
  <symbol id="svg-sun-half" viewBox="0 0 24 24">
    <title>Auto light/dark mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-shadow">
      <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
      <circle cx="12" cy="12" r="9" />
      <path d="M13 12h5" />
      <path d="M13 15h4" />
      <path d="M13 18h1" />
      <path d="M13 9h4" />
      <path d="M13 6h1" />
    </svg>
  </symbol>
  <symbol id="svg-sun-with-moon" viewBox="0 0 24 24">
    <title>Auto light/dark, in light mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
      class="icon-custom-derived-from-feather-sun-and-tabler-moon">
      <path style="opacity: 50%" d="M 5.411 14.504 C 5.471 14.504 5.532 14.504 5.591 14.504 C 3.639 16.319 4.383 19.569 6.931 20.352 C 7.693 20.586 8.512 20.551 9.25 20.252 C 8.023 23.207 4.056 23.725 2.11 21.184 C 0.166 18.642 1.702 14.949 4.874 14.536 C 5.051 14.512 5.231 14.5 5.411 14.5 L 5.411 14.504 Z"/>
      <line x1="14.5" y1="3.25" x2="14.5" y2="1.25"/>
      <line x1="14.5" y1="15.85" x2="14.5" y2="17.85"/>
      <line x1="10.044" y1="5.094" x2="8.63" y2="3.68"/>
      <line x1="19" y1="14.05" x2="20.414" y2="15.464"/>
      <line x1="8.2" y1="9.55" x2="6.2" y2="9.55"/>
      <line x1="20.8" y1="9.55" x2="22.8" y2="9.55"/>
      <line x1="10.044" y1="14.006" x2="8.63" y2="15.42"/>
      <line x1="19" y1="5.05" x2="20.414" y2="3.636"/>
      <circle cx="14.5" cy="9.55" r="3.6"/>
    </svg>
  </symbol>
  <symbol id="svg-moon-with-sun" viewBox="0 0 24 24">
    <title>Auto light/dark, in dark mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
      class="icon-custom-derived-from-feather-sun-and-tabler-moon">
      <path d="M 8.282 7.007 C 8.385 7.007 8.494 7.007 8.595 7.007 C 5.18 10.184 6.481 15.869 10.942 17.24 C 12.275 17.648 13.706 17.589 15 17.066 C 12.851 22.236 5.91 23.143 2.505 18.696 C -0.897 14.249 1.791 7.786 7.342 7.063 C 7.652 7.021 7.965 7 8.282 7 L 8.282 7.007 Z"/>
      <line style="opacity: 50%" x1="18" y1="3.705" x2="18" y2="2.5"/>
      <line style="opacity: 50%" x1="18" y1="11.295" x2="18" y2="12.5"/>
      <line style="opacity: 50%" x1="15.316" y1="4.816" x2="14.464" y2="3.964"/>
      <line style="opacity: 50%" x1="20.711" y1="10.212" x2="21.563" y2="11.063"/>
      <line style="opacity: 50%" x1="14.205" y1="7.5" x2="13.001" y2="7.5"/>
      <line style="opacity: 50%" x1="21.795" y1="7.5" x2="23" y2="7.5"/>
      <line style="opacity: 50%" x1="15.316" y1="10.184" x2="14.464" y2="11.036"/>
      <line style="opacity: 50%" x1="20.711" y1="4.789" x2="21.563" y2="3.937"/>
      <circle style="opacity: 50%" cx="18" cy="7.5" r="2.169"/>
    </svg>
  </symbol>
  <symbol id="svg-pencil" viewBox="0 0 24 24">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-pencil-code">
      <path d="M4 20h4l10.5 -10.5a2.828 2.828 0 1 0 -4 -4l-10.5 10.5v4" />
      <path d="M13.5 6.5l4 4" />
      <path d="M20 21l2 -2l-2 -2" />
      <path d="M17 17l-2 2l2 2" /
    </svg>
  </symbol>
  <symbol id="svg-eye" viewBox="0 0 24 24">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-eye-code">
      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
      <path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
      <path
        d="M11.11 17.958c-3.209 -.307 -5.91 -2.293 -8.11 -5.958c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6c-.21 .352 -.427 .688 -.647 1.008" />
      <path d="M20 21l2 -2l-2 -2" />
      <path d="M17 17l-2 2l2 2" />
    </svg>
  </symbol>
</svg>

<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation">
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc">
<label class="overlay sidebar-overlay" for="__navigation">
  <div class="visually-hidden">Hide navigation sidebar</div>
</label>
<label class="overlay toc-overlay" for="__toc">
  <div class="visually-hidden">Hide table of contents sidebar</div>
</label>

<a class="skip-to-content muted-link" href="#furo-main-content">Skip to content</a>



<div class="page">
  <header class="mobile-header">
    <div class="header-left">
      <label class="nav-overlay-icon" for="__navigation">
        <div class="visually-hidden">Toggle site navigation sidebar</div>
        <i class="icon"><svg><use href="#svg-menu"></use></svg></i>
      </label>
    </div>
    <div class="header-center">
      <a href="index.html"><div class="brand">🔥LIT 1.0 documentation</div></a>
    </div>
    <div class="header-right">
      <div class="theme-toggle-container theme-toggle-header">
        <button class="theme-toggle">
          <div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
          <svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
          <svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
          <svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
          <svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
        </button>
      </div>
      <label class="toc-overlay-icon toc-header-icon" for="__toc">
        <div class="visually-hidden">Toggle table of contents sidebar</div>
        <i class="icon"><svg><use href="#svg-toc"></use></svg></i>
      </label>
    </div>
  </header>
  <aside class="sidebar-drawer">
    <div class="sidebar-container">
      
      <div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
  
  
  <span class="sidebar-brand-text">🔥LIT 1.0 documentation</span>
  
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
  <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
  <input type="hidden" name="check_keywords" value="yes">
  <input type="hidden" name="area" value="default">
</form>
<div id="searchbox"></div><div class="sidebar-scroll"><div class="sidebar-tree">
  <ul class="current">
<li class="toctree-l1"><a class="reference external" href="https://pair-code.github.io/lit/">   Main Site</a></li>
<li class="toctree-l1"><a class="reference internal" href="getting_started.html">   Getting Started</a></li>
<li class="toctree-l1"><a class="reference internal" href="demos.html">   Examples</a></li>
<li class="toctree-l1"><a class="reference internal" href="ui_guide.html">   UI Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="components.html">   Components &amp; Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="api.html">   Python API</a></li>
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">   Frontend Development</a></li>
<li class="toctree-l1"><a class="reference internal" href="docker.html">   Running in Docker</a></li>
<li class="toctree-l1"><a class="reference internal" href="glossary.html">   Glossary</a></li>
<li class="toctree-l1"><a class="reference internal" href="faq.html">   FAQ</a></li>
<li class="toctree-l1"><a class="reference external" href="https://github.com/pair-code/lit">   GitHub</a></li>
</ul>

</div>
</div>

      </div>
      
    </div>
  </aside>
  <div class="main">
    <div class="content">
      <div class="article-container">
        <a href="#" class="back-to-top muted-link">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
            <path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12z"></path>
          </svg>
          <span>Back to top</span>
        </a>
        <div class="content-icon-container">
          <div class="view-this-page">
  <a class="muted-link" href="_sources/frontend_development.md.txt" title="View this page">
    <svg><use href="#svg-eye"></use></svg>
    <span class="visually-hidden">View this page</span>
  </a>
</div>
<div class="theme-toggle-container theme-toggle-content">
            <button class="theme-toggle">
              <div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
              <svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
              <svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
              <svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
              <svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
            </button>
          </div>
          <label class="toc-overlay-icon toc-content-icon" for="__toc">
            <div class="visually-hidden">Toggle table of contents sidebar</div>
            <i class="icon"><svg><use href="#svg-toc"></use></svg></i>
          </label>
        </div>
        <article role="main" id="furo-main-content">
          <section class="tex2jax_ignore mathjax_ignore" id="frontend-developer-guide">
<h1>Frontend Developer Guide<a class="headerlink" href="#frontend-developer-guide" title="Link to this heading">¶</a></h1>
<!--* freshness: { owner: 'lit-dev' reviewed: '2024-06-24' } *-->
<!-- [TOC] placeholder - DO NOT REMOVE -->
<p>This document aims to describe the current LIT frontend system, including
conventions, best practices, and gotchas.</p>
<section id="high-level-overview">
<h2>High Level Overview<a class="headerlink" href="#high-level-overview" title="Link to this heading">¶</a></h2>
<p>LIT is powered by two central pieces of tech -
<a class="reference external" href="https://lit-element.polymer-project.org/">lit-element</a> for components and HTML
rendering, and <a class="reference external" href="https://mobx.js.org/README.html">mobx</a> for observable-oriented
state management.</p>
<p>Lit-element is a simple, web-component based library for building small,
self-contained pieces of web functionality. It uses a template-string based
output to declaratively render small, isolated pieces of UI.</p>
<p>Mobx is a tool centered around observable data, and it makes managing state
simple and scalable.</p>
<p>We highly recommend reading the docs for both projects - they both have fairly
simple APIs and are easy to digest in comparison to some heavier-weight toolkits
like Angular.</p>
</section>
<section id="application-architecture">
<h2>Application Architecture<a class="headerlink" href="#application-architecture" title="Link to this heading">¶</a></h2>
<p>The LIT client frontend is roughly divided into three conceptual groups -
<strong>Modules</strong> (which render visualizations), <strong>Services</strong> (which manage data), and
the <strong>App</strong> itself (which coordinates initialization of services and determines
which modules to render).</p>
<section id="bootstrapping">
<h3>Bootstrapping<a class="headerlink" href="#bootstrapping" title="Link to this heading">¶</a></h3>
<p>The LIT app bootstrapping takes place in two steps: First, the served
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/static/index.html"><code class="docutils literal notranslate"><span class="pre">index.html</span></code></a>
page contains a single web component for the
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/core/lit_app.ts"><code class="docutils literal notranslate"><span class="pre">&lt;lit-app&gt;</span></code></a>.
This component is responsible for the overall layout of the app, including the
toolbar, footer, and the
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/core/modules.ts"><code class="docutils literal notranslate"><span class="pre">&lt;lit-modules&gt;</span></code></a>
component. The <code class="docutils literal notranslate"><span class="pre">&lt;lit-modules&gt;</span></code> component is responsible for actually laying out
and rendering the various <code class="docutils literal notranslate"><span class="pre">LitModule</span></code> components, a process about which we’ll go
into greater detail later.</p>
<p>The JS bundle entry point is
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/main.ts"><code class="docutils literal notranslate"><span class="pre">main.ts</span></code></a>, which first
imports the loaded, the <code class="docutils literal notranslate"><span class="pre">&lt;lit-app&gt;</span></code> web component is declared, and attaches
itself to the DOM, waiting for the app to be initialized.</p>
<p>The second step is kicking off app initialization. The
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/core/app.ts"><code class="docutils literal notranslate"><span class="pre">LitApp</span></code></a> singleton
class is provided with a layout declaring which <code class="docutils literal notranslate"><span class="pre">LitModule</span></code> components to use,
then builds the app services and kicks off app initialization and loading data.</p>
</section>
<section id="layout">
<h3>Layout<a class="headerlink" href="#layout" title="Link to this heading">¶</a></h3>
<p>A layout defines the arraignment of <code class="docutils literal notranslate"><span class="pre">LitModule</span></code> classes in the UI. Layouts are
specified in Python as <code class="docutils literal notranslate"><span class="pre">LitCanonicalLayout</span></code> instances, and LIT includes three
pre-configured layouts in
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/api/layout.py"><code class="docutils literal notranslate"><span class="pre">layout.py</span></code></a>:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">simple</span></code>: A minimalist layout with the examples on top (either individually
(selected by default) or in a table) and predictions on the bottom;</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">default</span></code>: The original LIT layout with a single group of modules on top for
exploring and selecting data, and a collection of tabs supporting different
analytical tasks on the bottom; and</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">three_panel</span></code>: A three-panel layout that puts exploratory data
visualizations at full-page height on the left, tools for inspecting and
manipulating examples and their associated predictions in the upper right,
and a collection of tabs supporting different analytical tasks in the lower
left. Note that this was introduced in v1.0 as an experimental feature, your
feedback is appreciated.</p></li>
</ul>
<p>You can also add <a class="reference internal" href="api.html#customizing-the-layout"><span class="std std-ref">custom layouts</span></a> to your LIT
instance by defining one or more <code class="docutils literal notranslate"><span class="pre">LitCanonicalLayout</span></code> instances and passing them
to the server. For an example, see
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/examples/prompt_debugging/layouts.py"><code class="docutils literal notranslate"><span class="pre">prompt_debugging/layouts.py</span></code></a>.</p>
<p>Note: The pre-configured layouts are added to every <code class="docutils literal notranslate"><span class="pre">LitApp</span></code> instance using
<a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#dict">dictionary updates</a> where
the Mapping passed to the <code class="docutils literal notranslate"><span class="pre">LitApp</span></code> constructor overrides the pre-configured
layouts <code class="docutils literal notranslate"><span class="pre">Mapping</span></code>. Thus, you can remove or change these pre-configured layouts
as you like by passing a <code class="docutils literal notranslate"><span class="pre">Mapping</span></code> where the values of <code class="docutils literal notranslate"><span class="pre">simple</span></code>, <code class="docutils literal notranslate"><span class="pre">default</span></code>,
and/or <code class="docutils literal notranslate"><span class="pre">three_panel</span></code> is <code class="docutils literal notranslate"><span class="pre">None</span></code> (to remove) or a <code class="docutils literal notranslate"><span class="pre">LitCanonicalLayout</span></code> instance
(to override) as you desire.</p>
<p>The actual layout of components in the LIT UI, see
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/core/modules.ts"><code class="docutils literal notranslate"><span class="pre">&lt;lit-modules&gt;</span></code></a>,
can be different than the declared layout, since the visibility of modules
depends on a number of factors, including the user-chosen visibility, the
compatibility of the configured modules with the selected model and dataset, and
whether or not specific modules show multiple copies per selected model. The
actual layout is computed in
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/services/modules_service.ts"><code class="docutils literal notranslate"><span class="pre">modules_service</span></code></a>.</p>
</section>
<section id="initialization">
<h3>Initialization<a class="headerlink" href="#initialization" title="Link to this heading">¶</a></h3>
<p>Finally, the LIT App initializes by building the various service classes and
starting the initial load of data from the server. This process consists of:</p>
<ol class="arabic simple">
<li><p>Parsing the URL query params to get the url configuration</p></li>
<li><p>Fetching the app metadata, which includes what models/datasets are available
to use.</p></li>
<li><p>Determining which models/datasets to load and then loading them.</p></li>
</ol>
</section>
</section>
<section id="modules-litmodule">
<h2>Modules (LitModule)<a class="headerlink" href="#modules-litmodule" title="Link to this heading">¶</a></h2>
<p>The
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/core/lit_module.ts"><code class="docutils literal notranslate"><span class="pre">LitModule</span></code></a>
is the base class from which all module components derive. It provides a number
of convenience methods for handling common update / data loading patterns. Each
LIT Module also requires a few static methods by convention, responsible for
specifying Module display and behavior. These helpers and conventions are
outlined below:</p>
<div class="highlight-typescript notranslate"><div class="highlight"><pre><span></span><span class="cm">/**</span>
<span class="cm"> * A dummy module that responds to changes in selected data by making a request</span>
<span class="cm"> * to an API service to get the pig latin translation.</span>
<span class="cm"> */</span>
<span class="kd">@customElement</span><span class="p">(</span><span class="s1">&#39;demo-module&#39;</span><span class="p">)</span><span class="w">                                                   </span><span class="c1">// (0)</span>
<span class="k">export</span><span class="w"> </span><span class="kd">class</span><span class="w"> </span><span class="nx">DemoTextModule</span><span class="w"> </span><span class="k">extends</span><span class="w"> </span><span class="nx">LitModule</span><span class="w"> </span><span class="p">{</span>
<span class="w">  </span><span class="k">static</span><span class="w"> </span><span class="kd">override</span><span class="w"> </span><span class="nx">title</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;Demo Module&#39;</span><span class="p">;</span><span class="w">                                        </span><span class="c1">// (1)</span>
<span class="w">  </span><span class="k">static</span><span class="w"> </span><span class="kd">override</span><span class="w"> </span><span class="nx">template</span><span class="w"> </span><span class="o">=</span>
<span class="w">      </span><span class="p">(</span><span class="nx">model</span><span class="o">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">selectionServiceIndex</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="p">,</span><span class="w"> </span><span class="nx">shouldReact</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w">    </span><span class="c1">// (2)</span>
<span class="w">          </span><span class="nx">html</span><span class="sb">`&lt;demo-module model=</span><span class="si">${</span><span class="nx">model</span><span class="si">}</span><span class="sb"> .shouldReact=</span><span class="si">${</span><span class="nx">shouldReact</span><span class="si">}</span>
<span class="sb">                selectionServiceIndex=</span><span class="si">${</span><span class="nx">selectionServiceIndex</span><span class="si">}</span><span class="sb">&gt;&lt;/demo-module&gt;`</span><span class="p">;</span>
<span class="w">  </span><span class="k">static</span><span class="w"> </span><span class="kd">override</span><span class="w"> </span><span class="nx">duplicateForModelComparison</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">true</span><span class="p">;</span><span class="w">                           </span><span class="c1">// (3)</span>

<span class="w">  </span><span class="k">static</span><span class="w"> </span><span class="kd">override</span><span class="w"> </span><span class="nx">get</span><span class="w"> </span><span class="nx">styles</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="p">[</span><span class="nx">styles</span><span class="p">];</span><span class="w">                                                            </span><span class="c1">// (4)</span>
<span class="w">  </span><span class="p">}</span>

<span class="w">  </span><span class="k">private</span><span class="w"> </span><span class="k">readonly</span><span class="w"> </span><span class="nx">colorService</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">app</span><span class="p">.</span><span class="nx">getService</span><span class="p">(</span><span class="nx">ColorService</span><span class="p">);</span><span class="w">                 </span><span class="c1">// (5)</span>

<span class="w">  </span><span class="kd">@observable</span><span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="nx">pigLatin</span><span class="o">:</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;&#39;</span><span class="p">;</span><span class="w">                                    </span><span class="c1">// (6)</span>

<span class="w">  </span><span class="kd">override</span><span class="w"> </span><span class="nx">firstUpdated</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">this</span><span class="p">.</span><span class="nx">reactImmediately</span><span class="p">(()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">selectionService</span><span class="p">.</span><span class="nx">primarySelectedInputData</span><span class="p">,</span><span class="w"> </span><span class="c1">// (7)</span>
<span class="w">      </span><span class="nx">primarySelectedInputData</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">this</span><span class="p">.</span><span class="nx">getTranslation</span><span class="p">(</span><span class="nx">primarySelectedInputData</span><span class="p">);</span>
<span class="w">      </span><span class="p">});</span>
<span class="w">  </span><span class="p">}</span>

<span class="w">  </span><span class="k">private</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="nx">getTranslation</span><span class="p">(</span><span class="nx">primarySelectedInputData</span><span class="o">:</span><span class="w"> </span><span class="kt">IndexedInput</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">primarySelectedInputData</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="k">return</span><span class="p">;</span>

<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">promise</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">apiService</span><span class="p">.</span><span class="nx">getPigLatin</span><span class="p">(</span><span class="nx">primarySelectedInputData</span><span class="p">);</span><span class="w">      </span><span class="c1">// (8)</span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">results</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">loadLatest</span><span class="p">(</span><span class="s1">&#39;pigLatin&#39;</span><span class="p">,</span><span class="w"> </span><span class="nx">promise</span><span class="p">);</span><span class="w">                 </span><span class="c1">// (9)</span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">results</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="k">return</span><span class="p">;</span>

<span class="w">    </span><span class="k">this</span><span class="p">.</span><span class="nx">pigLatin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">results</span><span class="p">;</span>
<span class="w">  </span><span class="p">}</span>

<span class="w">  </span><span class="kd">override</span><span class="w"> </span><span class="nx">renderImpl</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">                                                       </span><span class="c1">// (10)</span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">color</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">colorService</span><span class="p">.</span><span class="nx">getDatapointColor</span><span class="p">(</span>
<span class="w">        </span><span class="k">this</span><span class="p">.</span><span class="nx">selectionService</span><span class="p">.</span><span class="nx">primarySelectedInputData</span><span class="p">);</span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">html</span><span class="sb">`</span>
<span class="sb">      &lt;div class=&quot;results&quot; style=</span><span class="si">${</span><span class="nx">styleMap</span><span class="p">({</span><span class="s1">&#39;color&#39;</span><span class="o">:</span><span class="w"> </span><span class="nx">color</span><span class="si">}</span><span class="sb">)}&gt;</span>
<span class="sb">        </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">pigLatin</span><span class="si">}</span>
<span class="sb">      &lt;/div&gt;</span>
<span class="sb">    `</span><span class="p">;</span>
<span class="w">  </span><span class="p">}</span>

<span class="w">  </span><span class="k">static</span><span class="w"> </span><span class="nx">checkModule</span><span class="p">(</span><span class="nx">modelSpecs</span><span class="o">:</span><span class="w"> </span><span class="kt">ModelsMap</span><span class="p">,</span><span class="w"> </span><span class="nx">datasetSpec</span><span class="o">:</span><span class="w"> </span><span class="kt">Spec</span><span class="p">)</span><span class="o">:</span><span class="w"> </span><span class="kt">boolean</span><span class="w"> </span><span class="p">{</span><span class="w">       </span><span class="c1">// (11)</span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="kc">true</span><span class="p">;</span>
<span class="w">  </span><span class="p">}</span>
<span class="p">}</span>

<span class="kr">declare</span><span class="w"> </span><span class="nb">global</span><span class="w"> </span><span class="p">{</span><span class="w">                                                                </span><span class="c1">// (12)</span>
<span class="w">  </span><span class="kd">interface</span><span class="w"> </span><span class="nx">HTMLElementTagNameMap</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="s1">&#39;demo-module&#39;</span><span class="o">:</span><span class="w"> </span><span class="nx">DemoTextModule</span><span class="p">;</span>
<span class="w">  </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The above LitModule, while just a dummy example, illustrates all of the
necessary static properties and many of the most common patterns found in the
LIT app.</p>
<section id="setup">
<h3>Setup<a class="headerlink" href="#setup" title="Link to this heading">¶</a></h3>
<p>First, a <code class="docutils literal notranslate"><span class="pre">LitModule</span></code> must declare a static <code class="docutils literal notranslate"><span class="pre">title</span></code> string (1) and <code class="docutils literal notranslate"><span class="pre">template</span></code>
function (2). The <code class="docutils literal notranslate"><span class="pre">template</span></code> function determines how the modules layout renders
the component template and passes in module properties, such as the name of the
<code class="docutils literal notranslate"><span class="pre">model</span></code> this should respond to. (3) specified behavior in model comparison mode;
if duplicate is set to true, the layout engine will create two (or more)
instances of this module, each responsible for a different model.</p>
<p><em>Note: there are additional static attributes which control module behavior; see
the
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/core/lit_module.ts"><code class="docutils literal notranslate"><span class="pre">LitModule</span></code></a>
base class for full definitions.</em></p>
<p>Styles are also declared with a static get method (4), following the lit-element
convention. These styles can be built using the lit-element <code class="docutils literal notranslate"><span class="pre">css</span></code> template
function, or by importing a separate .css file. Styles can be shared between
components by importing a shared styles .css file (for instance,
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/lib/shared_styles.css"><code class="docutils literal notranslate"><span class="pre">shared_styles.css</span></code></a>)</p>
<p>Services are used by requesting them from the LitApp <code class="docutils literal notranslate"><span class="pre">app</span></code> singleton class (5).
This can be thought of as a super-simple dependency injection system, and allows
for much easier stubbing / mocking of services in testing. We request the
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/services/color_service.ts"><code class="docutils literal notranslate"><span class="pre">colorService</span></code></a>
here, but the base <code class="docutils literal notranslate"><span class="pre">LitModule</span></code> class initializes the most common services
(<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/services/api_service.ts"><code class="docutils literal notranslate"><span class="pre">apiService</span></code></a>,
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/services/state_service.ts"><code class="docutils literal notranslate"><span class="pre">appState</span></code></a>,
and
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/services/selection_service.ts"><code class="docutils literal notranslate"><span class="pre">selectionService</span></code></a>)
for us automatically.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">LitModule</span></code> must also provide a static <code class="docutils literal notranslate"><span class="pre">checkModule</span></code> (11) method, which
determines if this module should display for the given model(s) and dataset.</p>
<p>Finally, the <code class="docutils literal notranslate"><span class="pre">&#64;customElement('demo-module')</span></code> decorator (0) defines this class as
a custom HTML element <code class="docutils literal notranslate"><span class="pre">&lt;demo-module&gt;</span></code>, and (12) ensures this is accessible to
other TypeScript files in different build units.</p>
</section>
<section id="functionality">
<h3>Functionality<a class="headerlink" href="#functionality" title="Link to this heading">¶</a></h3>
<p>The above module has a very simple task - When the user selects input data, it
makes a request to an API service to fetch and display a pig latin translation
of the data. Since we’re using mobx observables to store and compute our state,
we do this all in a reactive way.</p>
<p>First, since the <code class="docutils literal notranslate"><span class="pre">LitModule</span></code> base class derives from <code class="docutils literal notranslate"><span class="pre">MobxLitElement</span></code>, any
observable data that we use in the <code class="docutils literal notranslate"><span class="pre">renderImpl</span></code> method automatically triggers a
re-render when updated. This is excellent for simple use cases, but what about
when we want to trigger more complex behavior, such as the asynchronous request
outlined above?</p>
<p>The pattern that we leverage across the app is as follows: The <code class="docutils literal notranslate"><span class="pre">renderImpl</span></code>
method (10) accesses a private observable <code class="docutils literal notranslate"><span class="pre">pigLatin</span></code> property (6) that, when
updated, will re-render the template and show the results of the translation
automatically. In order to update the <code class="docutils literal notranslate"><span class="pre">pigLatin</span></code> observable, we need to set up a
bit of machinery. In the lit-element lifecycle method <code class="docutils literal notranslate"><span class="pre">firstUpdated</span></code>, we use a
helper method <code class="docutils literal notranslate"><span class="pre">reactImmediately</span></code> (7) to set up an explicit reaction to the user
selecting data. Whatever is returned by the first function (in this case
<code class="docutils literal notranslate"><span class="pre">this.selectionService.primarySelectedInputData</span></code>) is observed and passed to the
second function immediately <strong>and</strong> whenever it changes, allowing us to do
something whenever the selection changes. Note, another helper method <code class="docutils literal notranslate"><span class="pre">react</span></code> is
used in the same way as <code class="docutils literal notranslate"><span class="pre">reactImmediately</span></code>, in instances where you don’t want to
immediately invoke the reaction. Also note that modules should override
<code class="docutils literal notranslate"><span class="pre">renderImpl</span></code> and not the base <code class="docutils literal notranslate"><span class="pre">render</span></code> method as our <code class="docutils literal notranslate"><span class="pre">LitModule</span></code> base class
overrides <code class="docutils literal notranslate"><span class="pre">render</span></code> with custom logic which calls our <code class="docutils literal notranslate"><span class="pre">renderImpl</span></code> method for
modules to perform their rendering in.</p>
<p>We pass the selection to the <code class="docutils literal notranslate"><span class="pre">getTranslation</span></code> method to fetch the data from our
API service. However rather than awaiting our API request directly, we pass the
request promise (8) to another helper method <code class="docutils literal notranslate"><span class="pre">loadLatest</span></code> (9). This ensures that
we won’t have any race conditions if, for instance, the user selects different
data rapidly - the function returns <code class="docutils literal notranslate"><span class="pre">null</span></code> when the request being fetched has
been superseded by a more recent call to the same endpoint. Finally, we set the
private <code class="docutils literal notranslate"><span class="pre">pigLatin</span></code> observable with the results of our API request and the
template is automatically rerendered, displaying our data.</p>
<p>This may seem like a bit of work for a simple module, but the pattern of using
purely observable data to declaratively specify what gets rendered is very
powerful for simplifying the logic around building larger, more complex
components.</p>
</section>
<section id="escape-hatches">
<h3>Escape Hatches<a class="headerlink" href="#escape-hatches" title="Link to this heading">¶</a></h3>
<p>Finally, it’s worth noting that the declarative template-based rendering setup,
while effective for handling most component render logic, is sometimes
inadequate for more advanced visualizations. In particular, the template
approach is not well suited for animations, rapidly changing data, or things
that MUST be done imperatively (such as drawing to a canvas). Fortunately, it’s
very easy to “bridge” from declarative to imperative code by leveraging the
lit-element lifecycle methods.</p>
<p>In particular, the <code class="docutils literal notranslate"><span class="pre">updated</span></code> and <code class="docutils literal notranslate"><span class="pre">firstUpdated</span></code> methods are useful for
explicitly doing work after the component has rendered. You can use normal
<code class="docutils literal notranslate"><span class="pre">querySelector</span></code> methods to select elements and update their properties
imperatively (note that you must make selections using the shadow root, not the
document, since we’re using isolated web components).</p>
<p>One important caveat is that messing with the actual structure of the rendered
DOM output (such as removing/reordering DOM nodes) <strong>will</strong> cause issues with
lit-element, since it relies on a consistent template output to do its
reconciliation of what needs to be updated per render.</p>
<div class="highlight-typescript notranslate"><div class="highlight"><pre><span></span><span class="c1">// An example of a LITModule imperative &quot;escape hatch&quot;</span>
<span class="w">  </span><span class="nx">updated</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">canvas</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">shadowRoot</span><span class="o">!</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">&#39;canvas&#39;</span><span class="p">);</span>
<span class="w">    </span><span class="k">this</span><span class="p">.</span><span class="nx">drawCanvas</span><span class="p">(</span><span class="nx">canvas</span><span class="p">);</span>
<span class="w">  </span><span class="p">}</span>

<span class="w">  </span><span class="kd">override</span><span class="w"> </span><span class="nx">renderImpl</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">html</span><span class="sb">`&lt;canvas&gt;&lt;/canvas&gt;`</span><span class="p">;</span>
<span class="w">  </span><span class="p">}</span>
</pre></div>
</div>
</section>
<section id="stateful-child-elements">
<h3>Stateful Child Elements<a class="headerlink" href="#stateful-child-elements" title="Link to this heading">¶</a></h3>
<p>Some modules may contain stateful child elements, where the element has some
internal state that can have an effect on the module that contains it. Examples
of this include any modules that contain the
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/core/faceting_control.ts">core/faceting_control.ts</a>
element.</p>
<p>With these types of child elements, it’s important for the containing module to
construct them programmatically and store them in a class member variable, as
opposed to only constructing them in the module’s html template string returned
by the <code class="docutils literal notranslate"><span class="pre">renderImpl</span></code> method. Otherwise they will be destroyed and recreated when
a module is hidden off-screen and then brought back on-screen, leading them to
lose whatever state they previously held. Below is a snippet of example code to
handle these types of elements.</p>
<div class="highlight-typescript notranslate"><div class="highlight"><pre><span></span><span class="c1">// An example of a LITModule using a stateful child element.</span>
<span class="kd">@customElement</span><span class="p">(</span><span class="s1">&#39;example-module&#39;</span><span class="p">)</span>
<span class="k">export</span><span class="w"> </span><span class="kd">class</span><span class="w"> </span><span class="nx">ExampleModule</span><span class="w"> </span><span class="k">extends</span><span class="w"> </span><span class="nx">LitModule</span><span class="w"> </span><span class="p">{</span>
<span class="w">  </span><span class="k">private</span><span class="w"> </span><span class="k">readonly</span><span class="w"> </span><span class="nx">facetingControl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">&#39;faceting-control&#39;</span><span class="p">);</span>

<span class="w">  </span><span class="kr">constructor</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">super</span><span class="p">();</span>

<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">facetsChange</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="nx">event</span><span class="o">:</span><span class="w"> </span><span class="kt">CustomEvent</span><span class="o">&lt;</span><span class="nx">FacetsChange</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">{</span>
<span class="w">      </span><span class="c1">// Do something with the information from the event.</span>
<span class="w">    </span><span class="p">};</span>
<span class="w">    </span><span class="c1">// Set the necessary properties on the faceting-control element.</span>
<span class="w">    </span><span class="k">this</span><span class="p">.</span><span class="nx">facetingControl</span><span class="p">.</span><span class="nx">contextName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">ExampleModule</span><span class="p">.</span><span class="nx">title</span><span class="p">;</span>
<span class="w">    </span><span class="k">this</span><span class="p">.</span><span class="nx">facetingControl</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span>
<span class="w">        </span><span class="s1">&#39;facets-change&#39;</span><span class="p">,</span><span class="w"> </span><span class="nx">facetsChange</span><span class="w"> </span><span class="kr">as</span><span class="w"> </span><span class="nx">EventListener</span><span class="p">)</span>
<span class="w">  </span><span class="p">}</span>

<span class="w">  </span><span class="kd">override</span><span class="w"> </span><span class="nx">renderImpl</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="c1">// Render the faceting-control element.</span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">html</span><span class="sb">`</span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">facetingControl</span><span class="si">}</span><span class="sb">`</span><span class="p">;</span>
<span class="w">  </span><span class="p">}</span>
</pre></div>
</div>
</section>
</section>
<section id="style-guide">
<h2>Style Guide<a class="headerlink" href="#style-guide" title="Link to this heading">¶</a></h2>
<ul>
<li><p>Please disable clang-format on <code class="docutils literal notranslate"><span class="pre">lit-html</span></code> templates and format these
manually instead:</p>
<div class="highlight-ts notranslate"><div class="highlight"><pre><span></span><span class="c1">// clang-format off</span>
<span class="k">return</span><span class="w"> </span><span class="nx">html</span><span class="sb">`</span>
<span class="sb">  &lt;div class=...&gt;</span>
<span class="sb">    &lt;button id=... @click=</span><span class="si">${</span><span class="nx">doSomething</span><span class="si">}</span><span class="sb">&gt;Foo&lt;/button&gt;</span>
<span class="sb">  &lt;/div&gt;</span>
<span class="sb">`</span><span class="p">;</span>
<span class="c1">// clang format on</span>
</pre></div>
</div>
</li>
<li><p>For new modules, in most cases you should implement two classes: one module
(subclassing
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/core/lit_module.ts"><code class="docutils literal notranslate"><span class="pre">LitModule</span></code></a>)
that interfaces with the LIT framework, and another element which subclasses
<code class="docutils literal notranslate"><span class="pre">LitElement</span></code>, <code class="docutils literal notranslate"><span class="pre">MobxLitElement</span></code>, or preferably,
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/lib/elements.ts?"><code class="docutils literal notranslate"><span class="pre">ReactiveElement</span></code></a>,
and implements self-contained visualization code. For an example, see
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/modules/annotated_text_module.ts">modules/annotated_text_module.ts</a>
and
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/elements/annotated_text_vis.ts">elements/annotated_text_vis.ts</a>.</p></li>
<li><p>On supported components (<code class="docutils literal notranslate"><span class="pre">ReactiveElement</span></code> and <code class="docutils literal notranslate"><span class="pre">LitModule</span></code>), use
<code class="docutils literal notranslate"><span class="pre">this.react()</span></code> or <code class="docutils literal notranslate"><span class="pre">this.reactImmediately()</span></code> instead of registering reactions
directly. This ensures that reactions will be properly cleaned up if the
element is later removed (such as a layout change or leaving comparison
mode).</p></li>
<li><p>Use
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/client/lib/shared_styles.css">shared styles</a>
when possible.</p></li>
</ul>
</section>
<section id="development-tips-open-source">
<h2>Development Tips (open-source)<a class="headerlink" href="#development-tips-open-source" title="Link to this heading">¶</a></h2>
<p>If you’re modifying any TypeScript code, you’ll need to re-build the frontend.
You can have yarn do this automatically. In one terminal, run:</p>
<div class="highlight-sh notranslate"><div class="highlight"><pre><span></span><span class="nb">cd</span><span class="w"> </span>~/lit/lit_nlp
yarn
yarn<span class="w"> </span>build<span class="w"> </span>--watch
</pre></div>
</div>
<p>And in the second, run the LIT server:</p>
<div class="highlight-sh notranslate"><div class="highlight"><pre><span></span><span class="nb">cd</span><span class="w"> </span>~/lit
python<span class="w"> </span>-m<span class="w"> </span>lit_nlp.examples.&lt;example_name&gt;<span class="w"> </span>--port<span class="o">=</span><span class="m">5432</span><span class="w"> </span><span class="o">[</span>optional<span class="w"> </span>--args<span class="o">]</span>
</pre></div>
</div>
<p>You can then access the LIT UI at <a class="reference external" href="http://localhost:5432">http://localhost:5432</a>.</p>
<p>If you only change frontend files, you can use <kbd>Ctrl/Cmd+Shift+R</kbd> to do
a hard refresh in your browser, and it should automatically pick up the updated
source from the build output.</p>
<p>If you’re modifying the Python backend, there is experimental support for
hot-reloading the LIT application logic (<code class="docutils literal notranslate"><span class="pre">app.py</span></code>) and some dependencies without
needing to reload models or datasets. See
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/dev_server.py"><code class="docutils literal notranslate"><span class="pre">dev_server.py</span></code></a> for
details.</p>
<p>You can use the <code class="docutils literal notranslate"><span class="pre">--data_dir</span></code> flag (see
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/server_flags.py"><code class="docutils literal notranslate"><span class="pre">server_flags.py</span></code></a> to
save the predictions cache to disk, and automatically reload it on a subsequent
run. In conjunction with <code class="docutils literal notranslate"><span class="pre">--warm_start</span></code>, you can use this to avoid re-running
inference during development - though if you modify the model at all, you should
be sure to remove any stale cache files.</p>
</section>
<section id="custom-client-modules">
<h2>Custom Client / Modules<a class="headerlink" href="#custom-client-modules" title="Link to this heading">¶</a></h2>
<p>The LIT frontend can be extended with custom visualizations or interactive
modules, though this is currently provided as “best effort” support and the API
is not as mature as for Python extensions.</p>
<p>An example of a custom LIT client application, including a custom
(potato-themed) module can be found in
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/examples/custom_module"><code class="docutils literal notranslate"><span class="pre">lit_nlp/examples/custom_module</span></code></a>.
You need only define any custom modules (subclass of <code class="docutils literal notranslate"><span class="pre">LitModule</span></code>) and include
them in the build.</p>
<p>When you build the app, specify the directory to build with the <code class="docutils literal notranslate"><span class="pre">env.build</span></code>
flag. For example, to build the <code class="docutils literal notranslate"><span class="pre">custom_module</span></code> demo app:</p>
<div class="highlight-sh notranslate"><div class="highlight"><pre><span></span>yarn<span class="w"> </span>build<span class="w"> </span>--env.build<span class="o">=</span>examples/custom_module
</pre></div>
</div>
<p>This builds the client app and moves all static assets to a <code class="docutils literal notranslate"><span class="pre">build</span></code> directory in
the specified directory containing the <code class="docutils literal notranslate"><span class="pre">main.ts</span></code> file
(<code class="docutils literal notranslate"><span class="pre">examples/custom_module/build</span></code>).</p>
<p>Finally, to serve the bundle, set the <code class="docutils literal notranslate"><span class="pre">client_root</span></code> flag in your python code to
point to this build directory. For this example we specify the build directory
in <code class="docutils literal notranslate"><span class="pre">examples/custom_module/potato_demo.py</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Here, client build/ is in the same directory as this file</span>
<span class="n">parent_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="vm">__file__</span><span class="p">)</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span>
<span class="n">FLAGS</span><span class="o">.</span><span class="n">set_default</span><span class="p">(</span><span class="s2">&quot;client_root&quot;</span><span class="p">,</span> <span class="n">parent_dir</span><span class="p">,</span> <span class="s2">&quot;build&quot;</span><span class="p">))</span>
</pre></div>
</div>
<p>You must also define a
<a class="reference internal" href="api.html#customizing-the-layout"><span class="std std-ref">custom layout definition</span></a> in Python which
references your new module. Note that because Python enums are not extensible,
you need to reference the custom module using its HTML tag name:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">modules</span> <span class="o">=</span> <span class="n">layout</span><span class="o">.</span><span class="n">LitModuleName</span>
<span class="n">POTATO_LAYOUT</span> <span class="o">=</span> <span class="n">layout</span><span class="o">.</span><span class="n">LitCanonicalLayout</span><span class="p">(</span>
    <span class="n">upper</span><span class="o">=</span><span class="p">{</span>
        <span class="s2">&quot;Main&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">modules</span><span class="o">.</span><span class="n">DatapointEditorModule</span><span class="p">,</span> <span class="n">modules</span><span class="o">.</span><span class="n">ClassificationModule</span><span class="p">],</span>
    <span class="p">},</span>
    <span class="n">lower</span><span class="o">=</span><span class="p">{</span>
        <span class="s2">&quot;Data&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">modules</span><span class="o">.</span><span class="n">DataTableModule</span><span class="p">,</span> <span class="s2">&quot;potato-module&quot;</span><span class="p">],</span>
    <span class="p">},</span>
    <span class="n">description</span><span class="o">=</span><span class="s2">&quot;Custom layout with our spud-tastic potato module.&quot;</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
</div>
<p>See
<a class="reference external" href="https://github.com/PAIR-code/lit/blob/main/lit_nlp/examples/custom_module/potato_demo.py"><code class="docutils literal notranslate"><span class="pre">potato_demo.py</span></code></a>
for the full example.</p>
</section>
</section>

        </article>
      </div>
      <footer>
        
        <div class="related-pages">
          <a class="next-page" href="docker.html">
              <div class="page-info">
                <div class="context">
                  <span>Next</span>
                </div>
                <div class="title">Running LIT in a Docker container</div>
              </div>
              <svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg>
            </a>
          <a class="prev-page" href="api.html">
              <svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg>
              <div class="page-info">
                <div class="context">
                  <span>Previous</span>
                </div>
                
                <div class="title">LIT Python API</div>
                
              </div>
            </a>
        </div>
        <div class="bottom-of-page">
          <div class="left-details">
            <div class="copyright">
                Copyright &#169; 2023, Google LLC
            </div>
            Made with <a href="https://www.sphinx-doc.org/">Sphinx</a> and <a class="muted-link" href="https://pradyunsg.me">@pradyunsg</a>'s
            
            <a href="https://github.com/pradyunsg/furo">Furo</a>
            
          </div>
          <div class="right-details">
            
          </div>
        </div>
        
      </footer>
    </div>
    <aside class="toc-drawer">
      
      
      <div class="toc-sticky toc-scroll">
        <div class="toc-title-container">
          <span class="toc-title">
            On this page
          </span>
        </div>
        <div class="toc-tree-container">
          <div class="toc-tree">
            <ul>
<li><a class="reference internal" href="#">Frontend Developer Guide</a><ul>
<li><a class="reference internal" href="#high-level-overview">High Level Overview</a></li>
<li><a class="reference internal" href="#application-architecture">Application Architecture</a><ul>
<li><a class="reference internal" href="#bootstrapping">Bootstrapping</a></li>
<li><a class="reference internal" href="#layout">Layout</a></li>
<li><a class="reference internal" href="#initialization">Initialization</a></li>
</ul>
</li>
<li><a class="reference internal" href="#modules-litmodule">Modules (LitModule)</a><ul>
<li><a class="reference internal" href="#setup">Setup</a></li>
<li><a class="reference internal" href="#functionality">Functionality</a></li>
<li><a class="reference internal" href="#escape-hatches">Escape Hatches</a></li>
<li><a class="reference internal" href="#stateful-child-elements">Stateful Child Elements</a></li>
</ul>
</li>
<li><a class="reference internal" href="#style-guide">Style Guide</a></li>
<li><a class="reference internal" href="#development-tips-open-source">Development Tips (open-source)</a></li>
<li><a class="reference internal" href="#custom-client-modules">Custom Client / Modules</a></li>
</ul>
</li>
</ul>

          </div>
        </div>
      </div>
      
      
    </aside>
  </div>
</div><script src="_static/documentation_options.js?v=f2a433a1"></script>
    <script src="_static/doctools.js?v=9a2dae69"></script>
    <script src="_static/sphinx_highlight.js?v=dc90522c"></script>
    <script src="_static/scripts/furo.js?v=4e2eecee"></script>
    </body>
</html>